﻿using Styx;
using Styx.Common;
using Styx.CommonBot;
using Styx.CommonBot.Routines;
using Styx.Pathing;
using Styx.TreeSharp;
using Action = Styx.TreeSharp.Action;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using Styx.CommonBot.Frames;
using System.Windows.Media;
using Bots.DungeonBuddy.Helpers;

namespace BMSVMM
{
    public partial class Main : CombatRoutine
    {
        #region take pet's target
        Composite TakeMyPetsTarget()
        {
            return new Action(ret =>
            {
                Me.Pet.CurrentTarget.Target(); 
                Logging.Write(Colors.Orange, "Taking my Pet's target"); 
                return RunStatus.Failure;
            });
        }
        #endregion

        #region AutoBot
        bool AutoBot
        {
            get
            {
                return usedBot.Contains("QUEST") || usedBot.Contains("GRIND") || usedBot.Contains("GATHER") || usedBot.Contains("ANGLER");

            }
        }
        #endregion

        #region slog
        private void slog(string msg)
        {
            Logging.Write(msg);
        }

        private void slog(string format, params object[] args)
        {
            Logging.Write(format, args);
        }
        #endregion

        #region Buff Checks

        public bool buffExists(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }

        public bool buffExists(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return true;
            }
            return false;
        }

        public double buffTimeLeft(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                {
                    if (Results.TimeLeft.TotalMilliseconds > 0)
                        return Results.TimeLeft.TotalMilliseconds;
                }
            }
            return 0;
        }



        public uint buffStackCount(int Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraById(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        public uint buffStackCount(string Buff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                var Results = onTarget.GetAuraByName(Buff);
                if (Results != null)
                    return Results.StackCount;
            }
            return 0;
        }
        #endregion

        #region Cache Checks
        public IEnumerable<WoWAura> cachedAuras = new List<WoWAura>();
        public IEnumerable<WoWAura> cachedTargetAuras = new List<WoWAura>();
        public void getCachedAuras()
        {
            if (Me.CurrentTarget != null)
                cachedTargetAuras = Me.CurrentTarget.GetAllAuras();
            cachedAuras = Me.GetAllAuras();
        }
        #endregion

        #region spellcolldown left
        public static TimeSpan GetSpellCooldown(string spell)
        {
            SpellFindResults results;
            if (SpellManager.FindSpell(spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Original.CooldownTimeLeft;
            }


            return TimeSpan.MaxValue;
        }
        #endregion

        #region Cooldown Checks
        private Dictionary<WoWSpell, long> Cooldowns = new Dictionary<WoWSpell, long>();
        public TimeSpan cooldownLeft(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan cooldownLeft(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.CooldownTimeLeft;
                    return TimeSpan.MaxValue;
                }
            }
            return TimeSpan.MaxValue;
        }
        long lastUsed;
        public int lastCast;
        public bool onCooldown(int Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public bool onCooldown(string Spell)
        {
            SpellFindResults Results;
            if (SpellManager.FindSpell(Spell, out Results))
            {
                WoWSpell Result = Results.Override ?? Results.Original;
                if (Cooldowns.TryGetValue(Result, out lastUsed))
                {
                    if (DateTime.Now.Ticks < lastUsed)
                        return Result.Cooldown;
                    return false;
                }
            }
            return false;
        }
        public TimeSpan spellCooldownLeft(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public TimeSpan spellCooldownLeft(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return cooldownLeft(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
            {
                if (results.Override != null)
                    return results.Override.CooldownTimeLeft;
                return results.Override.CooldownTimeLeft;
            }
            return TimeSpan.MaxValue;
        }
        public bool spellOnCooldown(int Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        public bool spellOnCooldown(string Spell, bool useTracker = false)
        {
            if (useTracker)
                return !onCooldown(Spell);
            SpellFindResults results;
            if (SpellManager.FindSpell(Spell, out results))
                return results.Override != null ? results.Override.Cooldown : results.Original.Cooldown;
            return false;
        }
        #endregion

        #region Debuff Checks

        public bool debuffExists(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.SpellId == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(int Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.SpellId == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        public bool debuffExists(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a => a.Name == Debuff && a.CreatorGuid == Me.Guid);
                if (aura != null)
                {
                    return true;
                }
            }
            return false;
        }

        public double debuffTimeLeft(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.TimeLeft.TotalMilliseconds;
            }
            return 0;
        }

        public uint debuffStackCount(string Debuff, WoWUnit onTarget)
        {
            if (onTarget != null)
            {
                WoWAura aura = onTarget.GetAllAuras().FirstOrDefault(a =>
                    a.Name == Debuff
                    && a.CreatorGuid == Me.Guid);

                if (aura == null)
                {
                    return 0;
                }
                return aura.StackCount;
            }
            return 0;
        }
        #endregion

        #region Timer Checks
        public bool isTargetDummy
        {
            get
            {
                return Me.CurrentTarget.Name.Contains("Dummy");
            }
        }
        private int conv_Date2Timestam(DateTime _time)
        {
            var date1 = new DateTime(1970, 1, 1);
            DateTime date2 = _time;
            var ts = new TimeSpan(date2.Ticks - date1.Ticks);
            return (Convert.ToInt32(ts.TotalSeconds));
        }
        private uint current_life;
        private int current_time;
        private ulong guid;
        private uint first_life;
        private uint first_life_max;
        private int first_time;
        public long targetExistence(WoWUnit onTarget)
        {
            if (onTarget == null) return 0;
            if (isTargetDummy) return 9999;
            if (onTarget.CurrentHealth == 0 || onTarget.IsDead || !onTarget.IsValid || !onTarget.IsAlive)
                return 0;
            if (guid != onTarget.Guid)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
            }
            current_life = onTarget.CurrentHealth;
            current_time = conv_Date2Timestam(DateTime.Now);
            var time_diff = current_time - first_time;
            var hp_diff = first_life - current_life;
            if (hp_diff > 0)
            {
                var full_time = time_diff * first_life_max / hp_diff;
                var past_first_time = (first_life_max - first_life) * time_diff / hp_diff;
                var calc_time = first_time - past_first_time + full_time - current_time;
                if (calc_time < 1) calc_time = 99;
                var time_to_die = calc_time;
                var fight_length = full_time;
                return time_to_die;
            }
            if (hp_diff < 0)
            {
                guid = onTarget.Guid;
                first_life = onTarget.CurrentHealth;
                first_life_max = onTarget.MaxHealth;
                first_time = conv_Date2Timestam(DateTime.Now);
                return -1;
            }
            if (current_life == first_life_max)
                return 9999;
            return -1;
        }
        #endregion

        #region cleartarget
        Composite ClearMyTarget()
        {
            return new PrioritySelector(
                new Action(ret =>
                {
                    Me.ClearTarget();
                    return RunStatus.Failure;
                })
                );
        }
        #endregion

        #region hastebuffs
        public string BLOODLUST = "Bloodlust";
        public string TIME_WARP = "Time Warp";
        public string HEROISM = "Heroism";
        public string DRUMS_OF_RAGE = "Drums of Rage";
        public bool NotHaveHasteBuffs()
        {
            return !buffExists(BLOODLUST, Me)
                && !buffExists(TIME_WARP, Me)
                && !buffExists(HEROISM, Me)
                && !buffExists(DRUMS_OF_RAGE, Me);
        }
        #endregion

        #region statsbuffs
        public string MOTW = "Mark of the Wild";
        public string LEGACY_OF_THE_EMPEOR = "Legacy of the Emperor";
        public string BLESSING_OF_KINGS = "Blessing of Kings";
        public bool NotHaveStatsBuffs()
        {
            return !buffExists(MOTW, Me)
                && !buffExists(LEGACY_OF_THE_EMPEOR, Me)
                && !buffExists(BLESSING_OF_KINGS, Me);
        }
        #endregion

        #region findtarget
        Composite FindTarget()
        {
            return new Action(ret =>
            {
                Me.ClearTarget();
                WoWUnit myTarget = ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null
                    && u.Attackable
                    && u.CanSelect
                    && (!u.IsPlayer || (u.IsPlayer && u.PvpFlagged && u.IsTargetingMeOrPet))
                    && !u.IsFriendly
                    && !u.IsDead
                    && !u.IsCritter
                    && !u.IsNonCombatPet
                    && u.DistanceSqr <= 40 * 40
                    && !Blacklist.Contains(u, BlacklistFlags.All))
                    .OrderBy(u => u.Distance)
                    .FirstOrDefault();
                if (myTarget != null)
                {
                    Logging.Write(Colors.PaleGreen, "Found new Target " + myTarget.Name);
                    myTarget.Target();
                }
                return RunStatus.Failure;
            });
        }
        Composite FindBgTarget()
        {
            return new Action(ret =>
            {
                WoWUnit myTarget = ObjectManager.GetObjectsOfType<WoWUnit>(true, false).Where(u => u != null
                    && u.Attackable
                    && u.CanSelect
                    && !u.IsFriendly
                    && !u.IsDead
                    && (u.IsPlayer || (u.IsTargetingMeOrPet && Me.CurrentMap.IsBattleground))
                    && !u.Mounted
                    && u.FactionId != Me.FactionId
                    && !u.IsCritter
                    && !u.IsNonCombatPet
                    && u.DistanceSqr <= 40 * 40
                    && !Blacklist.Contains(u, BlacklistFlags.All))
                    .OrderBy(u => u.Distance)
                    .FirstOrDefault();
                if (myTarget != null)
                {
                    Logging.Write(Colors.PaleGreen, "Found new BG Target " + myTarget.Name);
                    myTarget.Target();
                }
                return RunStatus.Failure;
            });
        }
        public bool ValidUnit(WoWUnit unit)
        {
            if (unit == null) { return false; }
            if (unit.IsDead) { return false; }
            if (unit.IsFriendly) { return false; }
            if (!unit.CanSelect) { return false; }
            if (!unit.Attackable) { return false; }
            if (unit.OwnedByRoot != null && unit.OwnedByRoot.IsPlayer && !unit.OwnedByRoot.IsMe) { return false; }
            if (unit.SummonedByUnit != null && unit.OwnedByRoot.IsPlayer && !unit.OwnedByRoot.IsMe) { return false; }
            if (unit.CreatedByUnit != null && unit.OwnedByRoot.IsPlayer && !unit.OwnedByRoot.IsMe) { return false; }
            if (unit.IsCritter) { return false; }
            if (unit.IsNonCombatPet) { return false; }
            if (Blacklist.Contains(unit, BlacklistFlags.All)) { return false; }
            return true;
        }
        #endregion

        #region flask buffs
        public int Flask_OF_THE_EARTH_BUFF = 105694;
        public int Flask_OF_THE_WARM_SUN_BUFF = 105691;
        public int FLASK_OF_WINTERS_BITE_BUFF = 105696;
        public int FLASK_OF_FALLING_LEAVES_BUFF = 105693;
        public int FLASK_OF_SPRING_BLOSSOMS_BUFF = 105689;

        public bool NotHaveFlaskBuff
        {
            get
            {
                return !buffExists(Flask_OF_THE_EARTH_BUFF, Me)
                    && !buffExists(Flask_OF_THE_WARM_SUN_BUFF, Me)
                    && !buffExists(FLASK_OF_WINTERS_BITE_BUFF, Me)
                    && !buffExists(FLASK_OF_FALLING_LEAVES_BUFF, Me)
                    && !buffExists(FLASK_OF_SPRING_BLOSSOMS_BUFF, Me);
            }
        }
        #endregion

        #region checks
        public bool MovingBack = false;
        void Checks()
        {
            if (Me.CurrentTarget != null)
            {
                if (Battlegrounds.IsInsideBattleground)
                {
                    if (Me.GotTarget &&
                        Me.CurrentTarget.IsPet)
                    {
                        Blacklist.Add(Me.CurrentTarget, TimeSpan.FromDays(1));
                        Me.ClearTarget();
                    }

                    if (Me.GotTarget && Me.CurrentTarget.Mounted)
                    {
                        Blacklist.Add(Me.CurrentTarget, TimeSpan.FromMinutes(1));
                        Me.ClearTarget();
                    }
                }

                if (Me.CurrentTarget.Guid != lastGuid)
                {
                    fightTimer.Reset();
                    lastGuid = Me.CurrentTarget.Guid;
                    pullTimer.Reset();
                    pullTimer.Start();

                }
                else
                {
                    if (pullTimer.ElapsedMilliseconds > 30 * 1000 && !isBoss)
                    {
                        slog("Cannot pull " + Me.CurrentTarget.Name + " now.  Blacklist for 15 seconds.");
                        Styx.CommonBot.Blacklist.Add(Me.CurrentTarget.Guid, System.TimeSpan.FromSeconds(15.00));
                        MovingBack = true;
                    }
                }
                if (Me.GotTarget && (!fightTimer.IsRunning || Me.CurrentTarget.Guid != lastGuid))
                {
                    fightTimer.Reset();
                    fightTimer.Start();
                    lastGuid = Me.CurrentTarget.Guid;
                }
                if (Me.CurrentTarget != null
                    && !isBoss
                    && fightTimer.ElapsedMilliseconds > 25 * 1000
                    && Me.CurrentTarget.HealthPercent > 95)
                {
                    slog(" This " + Me.CurrentTarget.Name + " is a bugged mob.  Blacklisting for 30 sec.");
                    MovingBack = true;
                    Blacklist.Add(Me.CurrentTarget.Guid, TimeSpan.FromSeconds(30.00));
                }
            }
        }
        #endregion

        #region attackpoint
        WoWPoint attackPoint
        {
            get
            {
                if (Me.CurrentTarget != null)
                {
                    return WoWMovement.CalculatePointFrom(Me.CurrentTarget.Location, MeleeRange);
                }
                else
                {
                    WoWPoint noSpot = new WoWPoint();
                    return noSpot;
                }
            }
        }
        #endregion

        #region move back
        Composite MovingBackwardsToClose()
        {
            return
                new Action(ret =>
                {
                    WoWMovement.Move(WoWMovement.MovementDirection.Backwards);
                    while (gotTarget && Me.CurrentTarget.IsAlive && Me.CurrentTarget.Distance <= 8)
                    {
                        break;
                    }
                    WoWMovement.MoveStop();
                    return RunStatus.Failure;
                });
        }
        #endregion

        #region rooted
        public bool MeRooted()
        {
            WoWAuraCollection Auras = StyxWoW.Me.GetAllAuras();
            foreach (WoWAura a in Auras)
            {
                if (a.Spell.Mechanic == WoWSpellMechanic.Frozen
                    || a.Spell.Mechanic == WoWSpellMechanic.Rooted)
                {
                    return true;
                }
            }
            return false;
        }
        Composite RemoveRooted()
        {
            return
                    new Action(ret =>
                    {
                        if (Me.Shapeshift == ShapeshiftForm.Cat)
                        {
                            Lua.DoString("RunMacroText(\"/Cast !Cat Form\")");
                        }
                        if (Me.Shapeshift == ShapeshiftForm.Bear)
                        {
                            Lua.DoString("RunMacroText(\"/Cast !Bear Form\")");
                        }
                        return RunStatus.Failure;
                    });
        }
        #endregion

        #region milliseconden
        static class CurrentMillis
        {
            private static readonly DateTime Jan1St1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            /// <summary>Get extra long current timestamp</summary>
            public static long Millis { get { return (long)((DateTime.UtcNow - Jan1St1970).TotalMilliseconds); } }
        }
        #endregion

        #region interruptspells
        public string _readPath = Path.Combine(Utilities.AssemblyDirectory, string.Format(@"Routines/Settings/Config/Pasterke/Interrupt.txt"));
        public string _writePath = Path.Combine(Utilities.AssemblyDirectory, string.Format(@"Routines/Settings/Config/Pasterke/"));
        public List<String> spellList = new List<string>();

        public void ReadInterruptList()
        {
            //create dir if not exists
            bool folderExists = Directory.Exists(_writePath);
            if (!folderExists)
                Directory.CreateDirectory(_writePath);

            //create file if not exists
            if (!File.Exists(_readPath))
            {
                File.Create(_readPath);
            }

            using (StreamReader lezer = new StreamReader(_readPath))
            {
                string line;
                while ((line = lezer.ReadLine()) != null)
                {
                    spellList.Add(line);
                }
            }
        }
        public bool CanInterrupt(string spell)
        {
            return spellList.Contains(spell);
        }
        #endregion

        #region loot
        private double LootRange
        {
            get { return LootTargeting.LootRadius; }
        }
        private IOrderedEnumerable<WoWUnit> Lootables
        {
            get
            {
                var targetsList = ObjectManager.GetObjectsOfType<WoWUnit>(false, false).Where(
                        p => (p.Lootable || p.CanSkin) && p.Distance <= LootRange).OrderBy(l => l.Distance);
                return targetsList;
            }
        }
        private void GetLoot()
        {
            if (Me.IsCasting || Lootables.Count() == 0 || Me.IsMoving)
                return;
            if (LootFrame.Instance != null && LootFrame.Instance.IsVisible)
            {
                LootFrame.Instance.LootAll();
                return;
            }
            var lootTarget = Lootables.FirstOrDefault();
            if (lootTarget.Distance > lootTarget.InteractRange && !Me.GroupInfo.IsInParty && !Me.GroupInfo.IsInRaid && !Me.IsInInstance)
            {
                slog("Moving to loot {0}.", lootTarget.Name);
                Navigator.MoveTo(lootTarget.Location);
            }
            else
            {
                lootTarget.Interact();
                return;
            }
        }
        #endregion loot

        #region facing
        Composite FaceMyTarget()
        {
            return new Action(ret =>
                    {
                        Me.CurrentTarget.Face();
                        return RunStatus.Failure;
                    });
        }
        #endregion

        #region Movement
        Composite CreateRangeMovementBehavior()
        {
            return new Action(ret =>
                    {
                        Navigator.MoveTo(Me.CurrentTarget.Location);
                        return RunStatus.Failure;
                    }
                );
        }
        Composite CreateStopMovementBehavior()
        {
            return new Action(ret =>

                    {
                        Navigator.PlayerMover.MoveStop();
                        return RunStatus.Failure;
                    }
                    );
        }
        #endregion

        #region use items
        Composite Trinket1()
        {
            return
                new Action(ret =>
                    {
                        var firstTrinket = StyxWoW.Me.Inventory.Equipped.Trinket1;


                        if (CRSettingsBMSVMM.myPrefs.Trinket1Use == CRSettingsBMSVMM.TrinketsUse.Below_HealthPercent
                            && Me.ManaPercent <= CRSettingsBMSVMM.myPrefs.trinket1hppercent
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            SetNexTrinketUseAllowed();
                            Logging.Write(Colors.DeepPink, "Using 1st Trinket");
                            return RunStatus.Success;
                        }
                        if (CRSettingsBMSVMM.myPrefs.Trinket1Use == CRSettingsBMSVMM.TrinketsUse.CrowdControlled
                            && IsCrowdControlledPlayer(Me)
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            SetNexTrinketUseAllowed();
                            Logging.Write(Colors.DeepPink, "Using 1st Trinket");
                            return RunStatus.Success;
                        }
                        if (CRSettingsBMSVMM.myPrefs.Trinket1Use == CRSettingsBMSVMM.TrinketsUse.DPS_Boost
                            && firstTrinket != null
                            && CanUseEquippedItem(firstTrinket))
                        {
                            firstTrinket.Use();
                            SetNexTrinketUseAllowed();
                            Logging.Write(Colors.DeepPink, "Using 1st Trinket");
                            return RunStatus.Success;
                        }
                        return RunStatus.Failure;
                    });
        }
        Composite Trinket2()
        {
            return
                    new Action(ret =>
                    {
                        var secondTrinket = StyxWoW.Me.Inventory.Equipped.Trinket2;


                        if (CRSettingsBMSVMM.myPrefs.Trinket2Use == CRSettingsBMSVMM.TrinketsUse.Below_HealthPercent
                            && Me.ManaPercent <= CRSettingsBMSVMM.myPrefs.trinket2hppercent
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            SetNexTrinketUseAllowed();
                            Logging.Write(Colors.DeepPink, "Using 2nd Trinket");
                            return RunStatus.Success;
                        }
                        if (CRSettingsBMSVMM.myPrefs.Trinket2Use == CRSettingsBMSVMM.TrinketsUse.CrowdControlled
                            && IsCrowdControlledPlayer(Me)
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            SetNexTrinketUseAllowed();
                            Logging.Write(Colors.DeepPink, "Using 2nd Trinket");
                            return RunStatus.Success;
                        }
                        if (CRSettingsBMSVMM.myPrefs.Trinket2Use == CRSettingsBMSVMM.TrinketsUse.DPS_Boost
                            && secondTrinket != null
                            && CanUseEquippedItem(secondTrinket))
                        {
                            secondTrinket.Use();
                            SetNexTrinketUseAllowed();
                            Logging.Write(Colors.DeepPink, "Using 2nd Trinket");
                            return RunStatus.Success;
                        }
                        return RunStatus.Failure;
                    });
        }
        Composite Healthstone()
        {
            return
                new Action(ret =>
                {
                    var hstone = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 5512);
                    if (hstone != null && hstone.Usable)
                    {
                        hstone.Use();
                        Logging.Write("Using Healthstone");
                        SetNextHealthstoneAllowed();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        Composite VirmenPotion()
        {
            return new Action(ret =>
            {
                var virmen = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 76093);
                if (virmen != null && virmen.Usable)
                {
                    virmen.Use();
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        Composite EngineerGloves()
        {
            return new Action(ret =>
            {
                var gloves = StyxWoW.Me.Inventory.Equipped.Hands;
                if (CRSettingsBMSVMM.myPrefs.GlovesChoice == CRSettingsBMSVMM.useEngiGloves.BossFights
                    && IsWoWBoss(Me.CurrentTarget) && CanUseEquippedItem(gloves) && gloves.Usable)
                {
                    gloves.Use();
                    SetNexEngiGlovesUseAllowed();
                    Logging.Write(Colors.DeepPink, "Using Engineer Gloves");
                    return RunStatus.Success;
                }
                if (CRSettingsBMSVMM.myPrefs.GlovesChoice == CRSettingsBMSVMM.useEngiGloves.OnCoolDown
                    && CanUseEquippedItem(gloves) && gloves.Usable)
                {
                    gloves.Use();
                    SetNexEngiGlovesUseAllowed();
                    Logging.Write(Colors.DeepPink, "Using Engineer Gloves");
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        private DateTime nextHealthstoneAllowed;

        public void SetNextHealthstoneAllowed()
        {
            nextHealthstoneAllowed = DateTime.Now + new TimeSpan(0, 0, 1, 59, 0);
        }
        private DateTime nextEngiGlovesUseAllowed;

        public void SetNexEngiGlovesUseAllowed()
        {
            nextEngiGlovesUseAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 25000);
        }

        private DateTime nextTrinketUseAllowed;
        public void SetNexTrinketUseAllowed()
        {
            nextTrinketUseAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 10000);
        }
        #endregion

        #region set wait time
        // returns true if we are pausing the rotation for Explosive Shot to come off cooldown
        private static bool NeedPause { get { return GetSpellCooldown("Explosive Shot").TotalMilliseconds < 300 && StyxWoW.Me.GetCurrentPower(WoWPowerType.Focus) >= 25; } }

        #endregion

        #region crowdcontrol

        public bool IsCrowdControlledTarget(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Fleeing
                || HasAuraWithEffect(unit,
                        WoWApplyAuraType.ModConfuse,
                        WoWApplyAuraType.ModCharm,
                        WoWApplyAuraType.ModFear,
                        WoWApplyAuraType.ModPossess);
        }

        public bool IsCrowdControlledPlayer(WoWUnit unit)
        {
            Dictionary<string, WoWAura>.ValueCollection auras = unit.Auras.Values;

            return unit.Stunned
                || unit.Rooted
                || unit.Fleeing
                || HasAuraWithEffect(unit,
                        WoWApplyAuraType.ModConfuse,
                        WoWApplyAuraType.ModCharm,
                        WoWApplyAuraType.ModFear,
                        WoWApplyAuraType.ModDecreaseSpeed,
                        WoWApplyAuraType.ModPacify,
                        WoWApplyAuraType.ModPacifySilence,
                        WoWApplyAuraType.ModPossess,
                        WoWApplyAuraType.ModRoot,
                        WoWApplyAuraType.ModStun);
        }

        // this one optimized for single applytype lookup
        public bool HasAuraWithEffect(WoWUnit unit, WoWApplyAuraType applyType)
        {
            return unit.Auras.Values.Any(a => a.Spell != null && a.Spell.SpellEffects.Any(se => applyType == se.AuraType));
        }

        public static bool HasAuraWithEffect(WoWUnit unit, params WoWApplyAuraType[] applyType)
        {
            var hashes = new HashSet<WoWApplyAuraType>(applyType);
            return unit.Auras.Values.Any(a => a.Spell != null && a.Spell.SpellEffects.Any(se => hashes.Contains(se.AuraType)));
        }
        #endregion

        #region do aeo
        public bool DoAoe
        {
            get
            {
                if (!SpellManager.HasSpell("Multi-Shot")) { return false; }
                if (PauseAoe) { return false; }
                if (UnfriendlyUnits.Count() < CRSettingsBMSVMM.myPrefs.StartAoe) { return false; }
                return true;
            }
        }
        #endregion do aoe

        #region HaveFishingRaft
        public bool HaveFishingRaft
        {
            get
            {
                var raft = ObjectManager.GetObjectsOfType<WoWItem>().FirstOrDefault(item => item.Entry == 85500);
                if (raft != null) { return true; }
                return false;
            }
        }
        #endregion

        #region use Burst Mode
        private DateTime nextBurstSpellAllowed;

        public void SetNexBurstSpellAllowed()
        {
            nextBurstSpellAllowed = DateTime.Now + new TimeSpan(0, 0, 0, 0, 1000);
        }

        string MURDER_OF_CROWS = "A Murder of Crows";
        string RAPID_FIRE = "Rapid Fire";
        string STAMPEDE = "Stampede";
        string BERSERKING = "Berserking";
        string BLOOD_FURY = "Blood Fury";
        Composite CastBurstMurderOfCrows()
        {
            return
                new Action(ret =>
            {
                if (SpellManager.CanCast(MURDER_OF_CROWS))
                {
                    SpellManager.Cast(MURDER_OF_CROWS);
                    Logging.Write(Colors.Bisque, MURDER_OF_CROWS + " Burst Mode");
                    SetNexBurstSpellAllowed();
                    return RunStatus.Success;
                }
                return RunStatus.Failure;
            });
        }
        Composite CastBurstStampede()
        {
            return
                new Action(ret =>
                {
                    if (SpellManager.CanCast(STAMPEDE))
                    {
                        SpellManager.Cast(STAMPEDE);
                        Logging.Write(Colors.Bisque, STAMPEDE + " Burst Mode");
                        SetNexBurstSpellAllowed();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        Composite CastBurstRapidFire()
        {
            return
                new Action(ret =>
                {
                    if (SpellManager.CanCast(RAPID_FIRE))
                    {
                        SpellManager.Cast(RAPID_FIRE);
                        Logging.Write(Colors.Bisque, RAPID_FIRE + " Burst Mode");
                        SetNexBurstSpellAllowed();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        Composite CastBurstBerserking()
        {
            return
                new Action(ret =>
                {
                    if (SpellManager.CanCast(BERSERKING))
                    {
                        SpellManager.Cast(BERSERKING);
                        Logging.Write(Colors.Bisque, BERSERKING + " Burst Mode");
                        SetNexBurstSpellAllowed();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        Composite CastBurstBloodFury()
        {
            return
                new Action(ret =>
                {
                    if (SpellManager.CanCast(BLOOD_FURY))
                    {
                        SpellManager.Cast(BLOOD_FURY);
                        Logging.Write(Colors.Bisque, BLOOD_FURY + " Burst Mode");
                        SetNexBurstSpellAllowed();
                        return RunStatus.Success;
                    }
                    return RunStatus.Failure;
                });
        }
        #endregion
    }
}
